home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Interactive Reference Guide
/
C-C++ Interactive Reference Guide.iso
/
c_ref
/
csource3
/
155_01
/
oned.c
< prev
next >
Wrap
Text File
|
1980-01-01
|
9KB
|
297 lines
/* HEADER: xxx.yy;
TITLE: ONED;
DATE: 4/30/85;
DESCRIPTION: "One dimensional cellular automata simulation";
VERSION: 1.0;
KEYWORDS: Life, cellular automata, games;
FILENAME: ONED.C;
CRC: xxxx;
SYSTEM: CP/M, Osborne 1;
COMPILERS: C/80;
AUTHORS: David L. Fox;
REFERENCES: AUTHORS: A. K. Dewdney;
TITLE: "Computer Recreations";
CITATION: "Scientific American, 252, 18-30(May 1985).";
AUTHORS: S. Wolfram;
TITLE: "Computer Software in Science and Mathematics";
CITATION: "Scientific American, 251, 188-203(September 1984).";
AUTHORS: S. Wolfram;
TITLE: "";
CITATION: "Physical Review Letters, 54, #8, 735-739(1985)."
ENDREF
*/
/* oned.c -- One dimensional cellular automata simulator.
Copyright 1985 by David L. Fox.
All rights reserved.
Permission granted for unlimited
personal and non-commercial use
provided that this notice is included.
*/
#include <stdio.h>
#include <printf.h>
#define MAXST 10 /* Maximum number of different states. */
#define MAXNB 10 /* Maximum number of neighboors (to one side). */
#define UNIVSIZ 250
#define SCRNSIZ 80 /* Number of characters in one line of display. */
/* Osborne 1 graphic characters to represent states. */
char stsym[] = {' ', '\0', '\026', '\015', '\014', '5', '6', '7', '8', '9'};
/* Osborne 1 screen controls (emulate Televideo 912 and 920. */
#define UPLINE "\013" /* Move cursor up one line. */
#define ERALINE "\033T" /* Erase from cursor to end of line. */
#define GPHST "\033g" /* Start display of graphics characters. */
#define GPHEND "\033G" /* End display of graphics characters. */
char pgmname[] = "ONED";
char copyright[] = "(c) Copyright 1985 David L. Fox";
char version[] = "1.0";
char univ[2][UNIVSIZ] /* Arrays for current and next generations. */
= {0,0,0,0,1,0,0,1,1,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,1,1,1,0,0,1};
int gen = 0; /* Generation index in univ. */
int origin = 0; /* Origin of displayed region. */
extern int (*CtlB)(); /* C/80 vectors here when ^B is pressed. */
int restart(); /* Called on ^B interrupt. */
char env[6]; /* Use #include <setjmp.h>
jmp_buf env;
with a fully UNIX compatable library. */
main(argc, argv)
int argc;
char **argv;
{ int ngen; /* Number of generations. */
int i, j;
char line[MAXSTR], *s;
static struct automaton {
int nstate; /* Number of possible states for each cell. */
int neighb; /* Number of neighbors on one side. */
int nexts[(MAXST - 1)*(2*MAXNB + 1) + 1]; /* Next state function. */
} ca = {2, 2, {0,0,1,0,1,0},}; /* r=2, s=2, code 20 automation. */
char *fgets();
printf("%s Version %s\n%s\n", pgmname, version, copyright);
CtlB = restart;
setjmp(env); /* Return here after interrupt. */
while ((printf(": "), s = fgets(line, MAXSTR, stdin)) != NULL) {
switch(*s) {
case 'a': /* Modify automaton. */
adisp(&ca);
break;
case 'd': /* Show current state of universe. */
printf(UPLINE);
dispst(univ[gen]);
break;
case 'e': /* Edit current state of universe. */
ued();
break;
case 'n': ++s; /* Do n generations. */
printf(UPLINE);
ngen = getval(&s);
evolve(ngen, &ca);
break;
case 'o': /* Shift origin. */
switch(*++s) {
case '=': origin = (getval(&s) + UNIVSIZ) % UNIVSIZ; break;
case '+': ++s; origin += getval(&s) % UNIVSIZ; break;
case '-': ++s; origin -= (getval(&s) - UNIVSIZ) % UNIVSIZ; break;
}
break;
case '\n':
printf(UPLINE);
evolve(1, &ca);
break;
case 'r':
++s;
if ((ca.neighb = getval(&s)) > MAXNB)
ca.neighb = MAXNB;
break;
case 's':
++s;
if ((ca.nstate = getval(&s)) > MAXST)
ca.nstate = MAXST;
break;
case 't':
if (*++s == '=') { /* Define transition table by t=code */
i = getval(&s);
for (j = 0; j <= (ca.nstate - 1)*(2*ca.neighb + 1) + 1; ++j) {
ca.nexts[j] = i % ca.nstate;
i /= ca.nstate;
}
}
else { /* Set members of transition table individually: txx=yy */
do {
if ((i = getval(&s)) > (ca.nstate-1)*(2*ca.neighb+1)) {
printf("total too large\n");
i = getval(&s);
continue;
}
if ((j = getval(&s)) < ca.nstate)
ca.nexts[i] = j;
else
printf("illegal state\n");
} while (*s);
}
break;
case 'x': exit();
default: printf("Unknown command: %s\n", s);
case '?': printf("Command summary\n\n ?\t\tDisplay this message.\n");
printf(" a\t\tDisplay automaton\n");
printf(" d\t\tDisplay state of universe.\n");
printf(" e\t\tEdit current state.\n");
printf(" n=xx\t\tCompute xx generations.\n");
printf(" o=xx\t\tSet display origin to xx.\n");
printf(" o+xx\t\tIncrease display origin to curent value + xx.\n");
printf(" o-xx\t\tDecrease display origin to curent value - xx.\n");
printf(" r=xx\t\tSet size of neighborhood.\n");
printf(" s=xx\t\tSet number of states.\n");
printf(" t=code\tTransition table given by code.\n");
printf(" txx=yy\tSet next state = yy for total xx.\n");
printf(" x\t\tExit to CP/M.\n");
}
}
}
/* getval -- Convert command string to a integer,
on exit strp contains pointer to next character to be processed. */
getval(strp)
char **strp;
{ char *s;
int n;
for (s = *strp; *s == '=' || *s == ',' || isspace(*s); ++s)
; /* Skip separators. */
n = atoi(s);
while (isdigit(*s))
++s;
*strp = s;
return(n);
}
/* evolve -- Compute next n generations of cellular automaton. */
evolve(n, ca)
int n;
struct automation *ca;
{ int i;
for (i=0; i < n; ++i) {
dogener(univ, ca);
gen = 1-gen;
dispst(univ[gen]);
}
}
/* dogener -- Compute next generation. */
dogener(univ, ca)
char univ[2][UNIVSIZ];
struct automaton *ca;
{ static int i, j, total; /* Static for speed. */
static char *uvp;
CtlCk(); /* C/80 routine to check for control characters. */
uvp = univ[gen];
for (i=0; i < UNIVSIZ; ++i) {
total = uvp[i];
for (j=1; j <= ca->neighb; ++j) {
total += ((i - j < 0) ? uvp[i-j+UNIVSIZ] : uvp[i-j]) +
((i + j >= UNIVSIZ) ? uvp[i+j-UNIVSIZ] : uvp[i+j]);
}
univ[1-gen][i] = ca->nexts[total];
}
}
/* dispst -- Display state of the universe. */
dispst(univ)
char univ[UNIVSIZ];
{ int i;
char c;
printf("%s", GPHST); /* Enter graphic mode. */
for (i=origin; i < origin+SCRNSIZ; ++i) {
putchar(stsym[univ[i % UNIVSIZ]]);
if (c = bdos(6, 0xff)) { /* Check for a character from keyboard. */
switch(c) {
case '\014': case '\04': /* Move display to right. */
origin = (origin + 1)%UNIVSIZ;
break;
case '\b': case '\023': /* Move display to left. */
origin = (origin - 1 + UNIVSIZ)%UNIVSIZ;
break;
}
}
}
printf("%s\n", GPHEND); /* Exit graphic mode, new line. */
}
/* ued -- Edit the current state of the universe. */
ued()
{ int curpos, i, c;
extern char Cmode;
Cmode = 0; /* Set char at a time input for C/80. */
curpos = 0;
printf("%s%s",UPLINE, UPLINE); /* Move up two lines. */
dispst(univ[gen]);
while (1) {
putchar('\r'); /* Return to left margin. */
for (i=0; i < curpos; ++i)
putchar(' ');
printf("^%s\b",ERALINE); /* Display cursor, erase to end of line. */
switch(c = getchar()) {
case '\b':
case '\023':
curpos = (curpos - 1 + UNIVSIZ)%UNIVSIZ;
break;
case '\014':
case '\04':
curpos = (curpos + 1)%UNIVSIZ;
break;
case ' ': /* Special case: blank = state 0. */
c = '0';
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
univ[gen][(curpos+origin)%UNIVSIZ] = c - '0';
printf("\r%s",UPLINE);
dispst(univ[gen]);
break;
case 'z': /* Zap universe. */
printf("\nZero entire universe (y/n)? ");
if ((c = toupper(getchar())) == 'Y')
for (i=0; i < UNIVSIZ; ++i)
univ[gen][i] = 0;
printf("\r%s%s",UPLINE, UPLINE);
dispst(univ[gen]);
printf("\n%s%s",ERALINE, UPLINE); /* Erase message. */
break;
case '\n':
printf(UPLINE);
default:
printf("\r%s", ERALINE); /* Erase cursor line. */
Cmode = 1; /* Restore line at a time input for C/80. */
return;
}
}
}
/* adisp -- Display properties of automaton. */
adisp(ca)
struct automaton *ca;
{ int i;
printf("origin=%d\n", origin);
printf("states=%d\nneighboors=%d\ntotal\tnext state\n", ca->nstate, ca->neighb);
for (i = 0; i < (ca->nstate - 1)*(2*ca->neighb + 1) + 1; ++i) {
printf("%d\t%d\n",i, ca->nexts[i]);
}
}
/* restart -- Control B vectors through CtlB to here. */
restart()
{ longjmp(env, 1); /* Restart program. */
}
#include "b:onedlib.c"
#include <stdlib.c>